`timescale 1ns / 1ps

`include "data_width.vh"

// 对带有复用信号的地址进行数据复用
module rd_src_p_reorder_block_128_3 #(parameter
    VERTEX_BRAM_DWIDTH = `VERTEX_BRAM_DWIDTH,
    REORDER_LOC_Y_WIDTH = `REORDER_LOC_Y_WIDTH,
    VERTEX_PIPE_NUM = `VERTEX_PIPE_NUM, EDGE_PIPE_NUM = `EDGE_PIPE_NUM,
    TOT_EDGE_MASK_WIDTH = `TOT_EDGE_MASK_WIDTH, TOT_ACC_ID_WIDTH = `TOT_ACC_ID_WIDTH,
    DST_ID_DWIDTH = `DST_ID_DWIDTH, VERTEX_MASK_WIDTH = `VERTEX_MASK_WIDTH,
    TOT_REUSE_WIDTH = `TOT_REUSE_WIDTH, REUSE_WIDTH = `REUSE_WIDTH
    ) (
        input clk,
        input rst,
        input [VERTEX_BRAM_DWIDTH * EDGE_PIPE_NUM - 1 : 0] front_src_p,
        input [TOT_REUSE_WIDTH - 1 : 0] front_reuse_info,
        input [EDGE_PIPE_NUM - 1 : 0] front_reuse_valid,
        input front_src_p_valid,
        input [TOT_EDGE_MASK_WIDTH - 1 : 0] front_tot_src_p_mask,
        input [TOT_ACC_ID_WIDTH - 1 : 0] front_tot_acc_id,
        input [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0] front_dst_id,
        input [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0] front_src_p_mask_r,
        input [VERTEX_PIPE_NUM - 1 : 0] front_dst_data_valid,
        input back_stage_edge_full,
        input back_stage_vertex_full,

        output buffer_full_vertex,
        output buffer_full_edge,
        output [VERTEX_BRAM_DWIDTH * EDGE_PIPE_NUM - 1 : 0] src_p,
        output src_p_valid,
        output [TOT_EDGE_MASK_WIDTH - 1 : 0] tot_src_p_mask,
        output [TOT_ACC_ID_WIDTH - 1 : 0] tot_acc_id,
        output [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0] dst_id,
        output [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0] src_p_mask_r,
        output [VERTEX_PIPE_NUM - 1 : 0] dst_data_valid);
    
    wire mask_buffer_empty, mask_buffer_full;
    wire [VERTEX_PIPE_NUM - 1 : 0] dst_buffer_empty, dst_buffer_full;
    wire any_front_dst_data_valid;
    wire edge_buffer_full;

    assign any_front_dst_data_valid = |front_dst_data_valid;
    assign buffer_full_vertex = dst_buffer_full[0];
    assign buffer_full_edge = edge_buffer_full;

    rd_src_p_reorder_block_128_3_edge E1 (
        .clk(clk), .rst(rst),
        .front_src_p(front_src_p), .front_src_p_valid(front_src_p_valid),
        .front_reuse_info(front_reuse_info), .front_reuse_valid(front_reuse_valid),
        .back_stage_edge_full(back_stage_edge_full),

        .buffer_full(edge_buffer_full),
        .src_p(src_p), .src_p_valid(src_p_valid));

    rd_src_p_reorder_block_128_3_mask M1 (
        .clk(clk), .rst(rst),
        .front_tot_src_p_mask(front_tot_src_p_mask), .front_tot_acc_id(front_tot_acc_id),
        .any_front_dst_data_valid(any_front_dst_data_valid), .back_stage_vertex_full(back_stage_vertex_full),

        .buffer_empty(mask_buffer_empty), .buffer_full(mask_buffer_full),
        .tot_src_p_mask(tot_src_p_mask), .tot_acc_id(tot_acc_id));

    generate
        genvar i;
        for (i = 0; i < VERTEX_PIPE_NUM; i = i + 1) begin : M11_3_BLOCK_1
            rd_src_p_reorder_block_128_3_vertex_single V (
                .clk(clk), .rst(rst),
                .front_dst_id(front_dst_id[(i + 1) * DST_ID_DWIDTH - 1 : i * DST_ID_DWIDTH]),
                .front_src_p_mask_r(front_src_p_mask_r[(i + 1) * VERTEX_MASK_WIDTH - 1 : i * VERTEX_MASK_WIDTH]),
                .front_dst_data_valid(front_dst_data_valid[i]),
                .any_front_dst_data_valid(any_front_dst_data_valid), .back_stage_vertex_full(back_stage_vertex_full),

                .buffer_empty(dst_buffer_empty[i]), .buffer_full(dst_buffer_full[i]),
                .dst_id(dst_id[(i + 1) * DST_ID_DWIDTH - 1 : i * DST_ID_DWIDTH]),
                .src_p_mask_r(src_p_mask_r[(i + 1) * VERTEX_MASK_WIDTH - 1 : i * VERTEX_MASK_WIDTH]),
                .dst_data_valid(dst_data_valid[i]));
        end
    endgenerate

endmodule

module rd_src_p_reorder_block_128_3_edge #(parameter
    REORDER_LOC_Y_WIDTH = `REORDER_LOC_Y_WIDTH,
    EDGE_PIPE_NUM = `EDGE_PIPE_NUM,
    VERTEX_BRAM_DWIDTH = `VERTEX_BRAM_DWIDTH,
    TOT_REUSE_WIDTH = `TOT_REUSE_WIDTH, REUSE_WIDTH = `REUSE_WIDTH
    ) (
        input clk,
        input rst,
        input [VERTEX_BRAM_DWIDTH * EDGE_PIPE_NUM - 1 : 0] front_src_p,
        input front_src_p_valid,
        input [TOT_REUSE_WIDTH - 1 : 0] front_reuse_info,
        input [EDGE_PIPE_NUM - 1 : 0] front_reuse_valid,
        input back_stage_edge_full,

        output buffer_full,
        output [VERTEX_BRAM_DWIDTH * EDGE_PIPE_NUM - 1 : 0] src_p,
        output reg src_p_valid);

    reg buffer_full_reg;
    reg src_p_valid_buffer;

    // 缓冲区写入
    always @ (posedge clk) begin
        if (rst) begin
            buffer_full_reg <= 1'b0;
            src_p_valid_buffer <= 1'b0;
        end
        else begin
            buffer_full_reg <= back_stage_edge_full;
            src_p_valid_buffer <= front_src_p_valid;
        end
    end
    generate
        genvar i;
        for (i = 0; i < EDGE_PIPE_NUM; i = i + 1) begin : M11_3_BLOCK_2
            rd_src_p_reorder_block_128_3_edge_single #(.LOC(i)) ES (
                .clk(clk), .rst(rst),
                .front_src_p(front_src_p), .front_src_p_valid(front_src_p_valid),
                .front_reuse_info_single(front_reuse_info[REUSE_WIDTH * (i + 1) - 1 : REUSE_WIDTH * i]), .front_reuse_valid_single(front_reuse_valid[i]),

                .src_p_single(src_p[VERTEX_BRAM_DWIDTH * (i + 1) - 1 : VERTEX_BRAM_DWIDTH * i]));
        end
    endgenerate

    assign buffer_full = buffer_full_reg;

    always @ (posedge clk) begin
        if (rst) begin
            src_p_valid <= 1'b0;
        end
        else begin
            src_p_valid <= src_p_valid_buffer;
        end
    end

endmodule

module rd_src_p_reorder_block_128_3_edge_single # (parameter
    LOC = 0,
    REORDER_LOC_Y_WIDTH = `REORDER_LOC_Y_WIDTH,
    EDGE_PIPE_NUM = `EDGE_PIPE_NUM,
    VERTEX_BRAM_DWIDTH = `VERTEX_BRAM_DWIDTH,
    REUSE_WIDTH = `REUSE_WIDTH
    ) (
        input clk,
        input rst,
        input [VERTEX_BRAM_DWIDTH * EDGE_PIPE_NUM - 1 : 0] front_src_p,
        input front_src_p_valid,
        input [REUSE_WIDTH - 1 : 0] front_reuse_info_single,
        input front_reuse_valid_single,

        output reg [VERTEX_BRAM_DWIDTH - 1 : 0] src_p_single);

    reg [VERTEX_BRAM_DWIDTH - 1 : 0] src_p_single_buffer;

    always @ (posedge clk) begin
        if (rst) begin
            src_p_single <= 0;
        end
        else begin
            src_p_single <= src_p_single_buffer;
        end
    end

    always @ (posedge clk) begin
        if (rst) begin
            src_p_single_buffer <= 0;
        end
        else begin
            if (front_src_p_valid && front_reuse_valid_single) begin
                case (front_reuse_info_single)
                    5'b00000: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH - 1 : 0];
                    end
                    5'b00001: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 2 - 1 : VERTEX_BRAM_DWIDTH];
                    end
                    5'b00010: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 3 - 1 : VERTEX_BRAM_DWIDTH * 2];
                    end
                    5'b00011: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 4 - 1 : VERTEX_BRAM_DWIDTH * 3];
                    end
                    5'b00100: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 5 - 1 : VERTEX_BRAM_DWIDTH * 4];
                    end
                    5'b00101: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 6 - 1 : VERTEX_BRAM_DWIDTH * 5];
                    end
                    5'b00110: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 7 - 1 : VERTEX_BRAM_DWIDTH * 6];
                    end
                    5'b00111: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 8 - 1 : VERTEX_BRAM_DWIDTH * 7];
                    end
                    5'b01000: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 9 - 1 : VERTEX_BRAM_DWIDTH * 8];
                    end
                    5'b01001: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 10 - 1 : VERTEX_BRAM_DWIDTH * 9];
                    end
                    5'b01010: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 11 - 1 : VERTEX_BRAM_DWIDTH * 10];
                    end
                    5'b01011: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 12 - 1 : VERTEX_BRAM_DWIDTH * 11];
                    end
                    5'b01100: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 13 - 1 : VERTEX_BRAM_DWIDTH * 12];
                    end
                    5'b01101: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 14 - 1 : VERTEX_BRAM_DWIDTH * 13];
                    end
                    5'b01110: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 15 - 1 : VERTEX_BRAM_DWIDTH * 14];
                    end
                    5'b01111: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 16 - 1 : VERTEX_BRAM_DWIDTH * 15];
                    end
                    5'b10000: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 17 - 1 : VERTEX_BRAM_DWIDTH * 16];
                    end
                    5'b10001: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 18 - 1 : VERTEX_BRAM_DWIDTH * 17];
                    end
                    5'b10010: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 19 - 1 : VERTEX_BRAM_DWIDTH * 18];
                    end
                    5'b10011: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 20 - 1 : VERTEX_BRAM_DWIDTH * 19];
                    end
                    5'b10100: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 21 - 1 : VERTEX_BRAM_DWIDTH * 20];
                    end
                    5'b10101: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 22 - 1 : VERTEX_BRAM_DWIDTH * 21];
                    end
                    5'b10110: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 23 - 1 : VERTEX_BRAM_DWIDTH * 22];
                    end
                    5'b10111: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 24 - 1 : VERTEX_BRAM_DWIDTH * 23];
                    end
                    5'b11000: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 25 - 1 : VERTEX_BRAM_DWIDTH * 24];
                    end
                    5'b11001: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 26 - 1 : VERTEX_BRAM_DWIDTH * 25];
                    end
                    5'b11010: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 27 - 1 : VERTEX_BRAM_DWIDTH * 26];
                    end
                    5'b11011: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 28 - 1 : VERTEX_BRAM_DWIDTH * 27];
                    end
                    5'b11100: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 29 - 1 : VERTEX_BRAM_DWIDTH * 28];
                    end
                    5'b11101: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 30 - 1 : VERTEX_BRAM_DWIDTH * 29];
                    end
                    5'b11110: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 31 - 1 : VERTEX_BRAM_DWIDTH * 30];
                    end
                    5'b11111: begin
                        src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * 32 - 1 : VERTEX_BRAM_DWIDTH * 31];
                    end
                endcase
            end
            else begin
                src_p_single_buffer <= front_src_p[VERTEX_BRAM_DWIDTH * (LOC + 1) - 1 : VERTEX_BRAM_DWIDTH * LOC];
            end
        end
    end
endmodule

module rd_src_p_reorder_block_128_3_mask #(parameter
    TOT_EDGE_MASK_WIDTH = `TOT_EDGE_MASK_WIDTH, TOT_ACC_ID_WIDTH = `TOT_ACC_ID_WIDTH
    ) (
        input clk,
        input rst,
        input [TOT_EDGE_MASK_WIDTH - 1 : 0] front_tot_src_p_mask,
        input [TOT_ACC_ID_WIDTH - 1 : 0] front_tot_acc_id,
        input any_front_dst_data_valid,
        input back_stage_vertex_full,

        output buffer_empty,
        output buffer_full,
        output [TOT_EDGE_MASK_WIDTH - 1 : 0] tot_src_p_mask,
        output [TOT_ACC_ID_WIDTH - 1 : 0] tot_acc_id);

    tot_edge_mask_fifo TEM1 (
        .clk(clk), .srst(rst),
        .din(front_tot_src_p_mask), .wr_en(any_front_dst_data_valid && !rst), .rd_en(!(buffer_empty || back_stage_vertex_full) && !rst),

        .dout(tot_src_p_mask), .empty(buffer_empty), .prog_full(buffer_full));

    tot_acc_id_fifo TAI1 (
        .clk(clk), .srst(rst),
        .din(front_tot_acc_id), .wr_en(any_front_dst_data_valid && !rst), .rd_en(!(buffer_empty || back_stage_vertex_full) && !rst),

        .dout(tot_acc_id));

endmodule

module rd_src_p_reorder_block_128_3_vertex_single #(parameter
    DST_ID_DWIDTH = `DST_ID_DWIDTH, VERTEX_MASK_WIDTH = `VERTEX_MASK_WIDTH
    ) (
        input clk,
        input rst,
        input [DST_ID_DWIDTH - 1 : 0] front_dst_id,
        input [VERTEX_MASK_WIDTH - 1 : 0] front_src_p_mask_r,
        input front_dst_data_valid,
        input any_front_dst_data_valid,
        input back_stage_vertex_full,

        output buffer_empty,
        output buffer_full,
        output [DST_ID_DWIDTH - 1 : 0] dst_id,
        output [VERTEX_MASK_WIDTH - 1 : 0] src_p_mask_r,
        output dst_data_valid);

    wire tmp_dst_data_valid_1, tmp_dst_data_valid_2;

    dst_id_fifo DI1 (
        .clk(clk), .srst(rst),
        .din(front_dst_id), .wr_en(any_front_dst_data_valid && !rst), .rd_en(!(buffer_empty || back_stage_vertex_full) && !rst),

        .dout(dst_id), .empty(buffer_empty), .prog_full(buffer_full));

    vertex_mask_fifo VM1 (
        .clk(clk), .srst(rst),
        .din(front_src_p_mask_r), .wr_en(!rst && any_front_dst_data_valid), .rd_en(!rst && !(buffer_empty || back_stage_vertex_full)),
        
        .dout(src_p_mask_r));

    dst_data_valid_fifo DDV1 (
        .clk(clk), .srst(rst),
        .din(front_dst_data_valid), .wr_en(any_front_dst_data_valid && !rst), .rd_en(!rst && !(buffer_empty || back_stage_vertex_full)),
        
        .dout(tmp_dst_data_valid_1), .valid(tmp_dst_data_valid_2));

    assign dst_data_valid = tmp_dst_data_valid_1 && tmp_dst_data_valid_2;

endmodule